#include "MarsPrecompile.h"

#include "MarsExample0.h"
#include "MarsRenderer.h"
#include "MarsGameObject.h"
#include "MarsMeshTriangle.h"
#include "MarsMaterial.h"
#include "MarsRenderable.h"
#include "MarsVertexShader.h"
#include "MarsPixelShader.h"
#include "MarsVertexData.h"
#include "MarsInputLayout.h"
#include "MarsVRamBuffer.h"
#include "MarsTexture.h"
#include "MarsSamplerState.h"
#include "MarsMeshCube.h"
#include "MarsConstantMgr.h"
#include "MarsCamera.h"
#include "MarsShaderMgr.h"
#include "MarsLight.h"
#include "MarsDirectionalLight.h"
#include "MarsSceneMgr.h"

using namespace App;
using namespace Core;
using namespace GameObject;

static Camera*	   s_pCamera	 = NULL;
static Mesh*	   s_pMesh		 = NULL;
static Material*   s_pMaterial	 = NULL;
static DirectionalLight* s_pDirectionLight = NULL;

static VertexShader* s_pVertexShader = NULL;
static PixelShader*  s_pPixelShader  = NULL;

static Texture*		 s_pDiffuseMap = NULL;
static SamplerState* s_pDiffuseSS = NULL;

static void CleanupStaticObject()
{
	SAFE_DELETE( s_pDirectionLight );
	SAFE_DELETE( s_pCamera );
	SAFE_DELETE( s_pMesh );
	SAFE_DELETE( s_pMaterial );
	SAFE_DELETE( s_pDiffuseMap );
	SAFE_DELETE( s_pDiffuseSS );
	SAFE_DELETE( s_pCamera );
}

MarsExample0::MarsExample0()
{

}

MarsExample0::~MarsExample0()
{

}

bool MarsExample0::LoadContent()
{
	bool bSuccess = false;

	struct CleanupObject
	{
		CleanupObject( bool* pSuccuss ) : m_pSuccess( pSuccuss )
		{}

		~CleanupObject() 
		{
			if ( !*m_pSuccess )
			{
				CleanupStaticObject();
			}
		}

		bool* m_pSuccess;
	} cleanupObject( &bSuccess );

	GameObject* pGameObject = SceneMgr::Instance().CreateGameObject( "Cube" );

	s_pMesh = new MeshCube();

	if ( !s_pMesh->Load() )
		return false;

	s_pVertexShader = static_cast< VertexShader* > ( ShaderMgr::Instance().LoadShader( 
		ShaderType_Vertex, 
		"res\\shaders\\DirectionalLight.fx", 
		"VS_Main", 
		"vs_4_0" ) );

	if ( !s_pVertexShader )
		return false;

	s_pPixelShader = static_cast< PixelShader* > ( ShaderMgr::Instance().LoadShader( 
		ShaderType_Pixel, 
		"res\\shaders\\DirectionalLight.fx", 
		"PS_Main", 
		"ps_4_0" ) );

	if ( !s_pPixelShader )
		return false;

	s_pMesh->GetVertexData()->GetInputLayout()->Bind( *s_pVertexShader );

	s_pDiffuseMap = new Texture( Texture::TT_2D, "res\\textures\\Default.dds" );
	if ( !s_pDiffuseMap->LoadTexture() )
		return false;

	D3D11_SAMPLER_DESC samplerDesc;
	MARS_MEMSET( &samplerDesc, 0, sizeof( D3D11_SAMPLER_DESC ) );
	samplerDesc.AddressU	   = D3D11_TEXTURE_ADDRESS_WRAP;
	samplerDesc.AddressV	   = D3D11_TEXTURE_ADDRESS_WRAP;
	samplerDesc.AddressW	   = D3D11_TEXTURE_ADDRESS_WRAP;
	samplerDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
	samplerDesc.Filter		   = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
	samplerDesc.MaxLOD		   = D3D11_FLOAT32_MAX;

	s_pDiffuseSS = new SamplerState(samplerDesc);
	if ( !s_pDiffuseSS->Create() )
		return false;

	s_pMaterial = new Material();
	s_pMaterial->SetVertexShader( s_pVertexShader );
	s_pMaterial->SetPixelShader( s_pPixelShader );
	s_pMaterial->SetDiffuseMap( s_pDiffuseMap, s_pDiffuseSS );

	s_pMaterial->SetAmbientColor( XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f ) );
	s_pMaterial->SetDiffuseColor( XMFLOAT4( 1.0f, 0.0f, 0.0f, 1.0f ) );
	s_pMaterial->SetSpecularColor( XMFLOAT4( 0.0f, 0.0f, 0.0f, 1.0f ) );
	s_pMaterial->SetShininess( 1.0f );

	Renderable* pRenderable = new Renderable( s_pMesh, s_pMaterial );

	pGameObject->AddComponent( pRenderable );

	s_pCamera = new Camera( Camera::PT_PERSPECTIVE );

	s_pDirectionLight = new DirectionalLight( XMFLOAT3( 0.0f, -1.0f, 0.0f ) );

	bSuccess = true;
	return bSuccess;
}

void MarsExample0::UnloadContent()
{
	CleanupStaticObject();
}

void MarsExample0::Update( float dt )
{
	s_pCamera->SetPosition( XMFLOAT3( 0.0f, 0.0f, -10.0f ), XMFLOAT3( 0.0f, 0.0f, 1.0f ) );
	SceneMgr::Instance().Update( dt );
}

void MarsExample0::Render()
{
	if ( !Renderer::Instance().IsReady() )
		return;

	float clearColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
	Renderer::Instance().ClearRenderTarget( clearColor );
	Renderer::Instance().ClearDepthStencil( 1.0f, 0 );

	SceneMgr::Instance().Render( *s_pCamera );

	Renderer::Instance().Present();
}